package cn.springsoter.core.tool.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Map;
import java.util.SortedMap;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Maps;

import lombok.extern.slf4j.Slf4j;

/**
 * http 工具类 获取请求中的参数
 * 
 * @author kevin
 */
@Slf4j
public class HttpUtil {
	private HttpUtil() {}
	
    /**
     * 获取post的返回值
     * 
     * @param requestBody
     * @param httpUrl
     * @param method	{@link HttpMethod}
     * @param hostHeader
     * @return
     * @throws Exception
     */
    public static JsonNode httpReturn(String requestBody, String httpUrl, HttpMethod method, String hostHeader) throws Exception{
        //headers
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=utf-8");
        requestHeaders.add(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
        if(StringUtils.isNotBlank(hostHeader)) {
        	requestHeaders.add(HttpHeaders.HOST, hostHeader);
        }
        //5秒
        int timeout = 5000;
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(timeout);
        requestFactory.setReadTimeout(timeout);
        //HttpEntity
        HttpEntity<String> requestEntity;
        RestTemplate restTemplate = new RestTemplate(requestFactory);

        ResponseEntity<String> responseEntity;
        JsonNode jsonObject = null;
        int retry = 0, maxRetry=2;
        //解决RestTemplate中headers中添加Host不生效的问题
        System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
        while (retry < maxRetry) {
            try {
                log.debug("begin invoke url：" + httpUrl + "，requestBody：" + requestBody);
                if (method == HttpMethod.GET) {
                    requestEntity = new HttpEntity<>("", requestHeaders);
                    responseEntity = restTemplate.exchange(httpUrl, HttpMethod.GET, requestEntity, String.class);
                } else {
                    requestEntity = new HttpEntity<>(requestBody, requestHeaders);
                    responseEntity = restTemplate.postForEntity(httpUrl, requestEntity, String.class);
                }
                jsonObject = JacksonUtil.toJsonNode(responseEntity.getBody());
                
                log.debug(responseEntity.toString());
                if (String.valueOf(jsonObject.get("code")).equals("0")){
                    break;
                }
            }catch (Exception e){
                log.error(ExceptionUtils.getStackTrace(e));
                throw e;
            }
            retry++;
        }//while
        return jsonObject;
    }
    
    /**
     * 将Get URL的参数和body参数合并
     * 
     * @param request
     * @return
     * @throws IOException
     */
    public static SortedMap<String, String> getAllParams(HttpServletRequest request) throws IOException {
        SortedMap<String, String> result = Maps.newTreeMap();
        //获取URL上的参数
        Map<String, String> urlParams = getUrlParams(request);
        for (Map.Entry entry : urlParams.entrySet()) {
            result.put(entry.getKey().toString(), entry.getValue().toString());
        }
        
        Map<String, String> allRequestParam = Maps.newHashMap();
        //获取body
        if (!HttpMethod.GET.name().equals(request.getMethod())) {
            allRequestParam = getBodyToMap(request);
        }
        //将URL的参数和body参数进行合并
        if (allRequestParam != null) {
            for (Map.Entry entry : allRequestParam.entrySet()) {
                result.put(entry.getKey().toString(), entry.getValue().toString());
            }
        }
        return result;
    }

    /**
     * 获取Body参数，返回Map
     * 注：使用此方法前，需要先把body的流复制一份出来，不然会报错。一次请求，body只允许读一次
     * 
     * @param request
     * @return	返回Map
     * @throws IOException
     */
    public static Map<String, String> getBodyToMap(final HttpServletRequest request) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String str = "";
        StringBuilder wholeStr = new StringBuilder();
        //一行一行的读取body体里面的内容；
        while ((str = reader.readLine()) != null) {
            wholeStr.append(str);
        }
        if(StringUtils.isNotBlank(wholeStr.toString())) {
        	//转化成Map
        	return JacksonUtil.toStringMap(wholeStr.toString());
        }
        return null;
    }
    
    /**
     * 获取Body参数，返回String
     * 注：使用此方法前，需要先把body的流复制一份出来，不然会报错。一次请求，body只允许读一次
     * 
     * @param request
     * @return	返回String
     * @throws IOException
     */
    public static String getBodyToString(final HttpServletRequest request) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String str = "";
        StringBuilder wholeStr = new StringBuilder();
        //一行一行的读取body体里面的内容；
        while ((str = reader.readLine()) != null) {
            wholeStr.append(str);
        }
        if(StringUtils.isNotBlank(wholeStr.toString())) {
        	//转化成String
        	return wholeStr.toString();
        }
        return null;
    }
    
    /**
     * 将Get URL请求参数转换成Map
     * 
     * @param request
     * @return
     */
    public static Map<String, String> getUrlParams(HttpServletRequest request) {
    	String query = request.getQueryString();
    	Map<String, String> result = Maps.newHashMap();
    	
    	if(StringUtils.isNotBlank(query)) {
	        String param = "";
	        try {
	        	param = URLDecoder.decode(query, "utf-8");
	        } catch (UnsupportedEncodingException e) {
	            log.error(ExceptionUtils.getStackTrace(e));
	        }
	        String[] params = param.split("&");
	        for (String s : params) {
	            int index = s.indexOf("=");
	            result.put(s.substring(0, index), s.substring(index + 1));
	        }
    	}
    	return result;
    }
}
